package cn.dengta.webapp.user.entity;

import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import cn.dengta.common.model.*;
import cn.dengta.webapp.base.entity.BaseEntity;
import com.alibaba.fastjson.annotation.JSONType;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import me.codeplayer.util.*;
import org.apache.commons.lang3.StringUtils;

/**
 * 文件类型表
 */
@Getter
@Setter
@Accessors(chain = true)
@JSONType(includes = { "name", "alias", "required" })
public class FileBizType extends BaseEntity {

	/** 允许上传的图片文件类型 */
	public static final String imageExts = ".jpg.png.jpeg.gif.bmp.svg.webp";
	/** 允许上传的视频类型 */
	public static final String videoExts = ".mp4";
	/** 允许上传的音频类型 */
	public static final String audioExts = ".aac";
	/** 1 MB 的字节数 */
	public static final long MB = 1024 * 1024;
	/** 允许上传的单个文件大小的最大值：【5MB】 */
	public static final long defaultSingleFileMax = MB * 5;
	//
	/** 中文含义 */
	protected String name;
	/** 别名（不可随意修改） */
	protected String alias;
	/** 描述 */
	protected String info;
	/** 文件业务配置 */
	protected FileBizConfig config;
	/** 是否必需 */
	protected Integer required;
	/** 排序值 */
	protected Integer sort;
	/** 业务状态 */
	protected Integer status;

	public FileBizType init(String alias, String name, String info, FileBizConfig config, Integer required, Integer sort, Integer status) {
		this.name = name;
		this.alias = alias;
		this.info = StringUtil.toString(info);
		this.config = config;
		this.required = required;
		this.sort = sort;
		this.status = status;
		return this;
	}

	public FileBizType init(String alias, String name, String info, FileBizConfig config) {
		return init(alias, name, info, config, Status.NO.value, 99, Status.YES.value);
	}

	public FileBizType init(String alias, String name) {
		return init(alias, name, "", new FileBizConfig().init());
	}

	/**
	 * 根据文件扩展名判断是否属于期望的文件类型
	 */
	public static boolean isImageType(String ext, boolean lowerAlready) {
		return matchFileType(imageExts, ext, lowerAlready);
	}

	/**
	 * 根据文件名称判断是否属于期望的文件类型
	 */
	public static boolean isImageType(String filename) {
		return isImageType(FileUtil.getExtension(filename, true), false);
	}

	/**
	 * 根据文件扩展名判断是否属于期望的文件类型
	 */
	public static boolean matchFileType(String allowedExts, String ext, boolean lowerAlready) {
		if (StringUtil.startsWith(ext, '.')) {
			ext = ext.substring(1);
		}
		if (StringUtil.isEmpty(ext)) {
			return false;
		}
		if (!lowerAlready) {
			ext = ext.toLowerCase();
		}
		return StringUtil.containsWord(allowedExts, ext, ".");
	}

	/**
	 * 检测文件名是否合法（是否存在非法字符）
	 */
	public static boolean isValidFilename(String filename) {
		if (StringUtils.containsAny(filename, '\\', '/')) {
			return false;
		}
		final char last = filename.charAt(filename.length() - 1);
		return last != '.' && !Character.isWhitespace(last);
	}

	/**
	 * 根据文件名称判断是否属于期望的文件类型
	 */
	public boolean matchFileType(String filename) {
		return matchFileType(config.fileExts, FileUtil.getExtension(filename), false);
	}

	/**
	 * 根据文件名称判断是否属于期望的文件类型
	 */
	public boolean matchFileSize(long fileSize) {
		return fileSize <= config.singleFileMax;
	}

	/**
	 * 根据文件名称判断是否属于期望的文件类型
	 */
	public void checkFileSize(long fileSize) {
		if (matchFileSize(fileSize)) {
			throw exceptionOnSingleFileSize();
		}
	}

	public boolean isOptional() {
		return Status.YES.value.equals(required);
	}

	/**
	 * 根据文件名称判断是否属于期望的文件类型
	 */
	public IllegalArgumentException exceptionOnSingleFileSize() {
		throw new IllegalArgumentException("上传的单个文件大小不能超过" + FileUtil.calcFileSize(config.singleFileMax, FileUtil.UNIT_MB));
	}

	/** 默认文件类型配置 */
	public static final FileBizType common = new FileBizType().init("common", "通用", "", FileBizConfig.DEFAULT);
	/** 唯一文件类型配置 */
	public static final FileBizType unique = new FileBizType().init("unique", "通用", "", FileBizConfig.UNIQUE);
	/** 默认视频文件类型配置 */
	public static final FileBizType video = new FileBizType().init("video", "视频", "", FileBizConfig.VIDEO_DEFAULT);
	/** 游戏相关 配置 */
	public static final FileBizType game = new FileBizType().init("game", "通用", "", FileBizConfig.of(1, 1));

	static final ConcurrentMap<String, FileBizType> configs = new ConcurrentHashMap<>();

	static {
		init();
	}

	protected static void put(FileBizType bizType) {
		configs.put(bizType.alias, bizType);
	}

	protected static void put(String alias, String name, String info, FileBizConfig config) {
		put(new FileBizType().init(alias, name, info, config));
	}

	protected static void put(FileBizKey bizKey, String info, FileBizConfig config) {
		put(new FileBizType().init(bizKey.getValue(), bizKey.getLabel(), info, config));
	}

	protected static void init() {
		put(FileBizKey.avatar, "", FileBizConfig.UNIQUE);
		put(FileBizKey.idCard, "", FileBizConfig.DEFAULT);
		put(FileBizKey.moments, "", FileBizConfig.of(1, 9));
		put(FileBizKey.photo, "", FileBizConfig.of(1, 15));
		put(FileBizKey.avatarCert, "", FileBizConfig.UNIQUE);
		put(FileBizKey.feedback, "", FileBizConfig.COMMON);
		put(FileBizKey.gift, "", FileBizConfig.UNIQUE);
		// 默认 15MB
		put(FileBizKey.svga, "", new FileBizConfig().init(1, 1, ".svga.mp4", defaultSingleFileMax * 3, defaultSingleFileMax * 3));
		put(FileBizKey.configImg, "", FileBizConfig.of(1, 5));
		put(FileBizKey.agent, "", FileBizConfig.of(1, 5));
		put(FileBizKey.groupAvatar, "", FileBizConfig.UNIQUE);
		put(FileBizKey.banner, "", FileBizConfig.UNIQUE);
		put(FileBizKey.startConfig, "", FileBizConfig.UNIQUE);
		put(FileBizKey.greet, "", FileBizConfig.UNIQUE);
		put(FileBizKey.tag, "", FileBizConfig.UNIQUE);
		put(FileBizKey.single, "", FileBizConfig.UNIQUE);
		put(FileBizKey.chatPhoto, "", FileBizConfig.UNIQUE);
		put(FileBizType.video);
		put(FileBizType.game);
		put(FileBizKey.payRisk, "", new FileBizConfig().init(1, 1, videoExts + audioExts, defaultSingleFileMax, defaultSingleFileMax));
		put(FileBizKey.payRiskRecord, "", new FileBizConfig().init(1, 1, imageExts, defaultSingleFileMax, defaultSingleFileMax));
	}

	public static FileBizType getByBizType(String bizType, boolean flush) {
		if (!X.isValid(configs) || flush) {
			init();
		}
		return configs.get(bizType);
	}

	@Getter
	@Setter
	@Accessors(chain = true)
	@JSONType(includes = { "minCount", "maxCount", "fileExts", "singleFileMax", "totalFileMax" })
	public static class FileBizConfig {

		public static final FileBizConfig UNIQUE = new FileBizConfig().init(1, 1, imageExts, defaultSingleFileMax, defaultSingleFileMax);
		/** 默认文件类型配置 */
		public static final FileBizConfig DEFAULT = new FileBizConfig().init();
		/** 默认文件类型配置 */
		public static final FileBizConfig COMMON = FileBizConfig.of(1, 5);
		/** 默认视频文件类型配置 */
		public static final FileBizConfig VIDEO_DEFAULT = new FileBizConfig().init(1, 1, videoExts, MB * 40, MB * 40);

		/** 一次性需要上传的最小文件数 */
		protected Integer minCount;
		/** 单笔业务允许上传的最大文件数 */
		protected Integer maxCount;
		/** 允许的文件扩展名 */
		protected String fileExts;
		/** 允许上传的单个文件大小的最大值（单位：byte） */
		protected long singleFileMax;
		/** 单笔业务允许上传的文件总大小（单位：byte） */
		protected long totalFileMax;

		public FileBizConfig init(Integer minCount, Integer maxCount, String fileExts, long singleFileMax, long totalFileMax) {
			this.minCount = minCount;
			this.maxCount = maxCount;
			this.fileExts = fileExts;
			this.singleFileMax = singleFileMax;
			this.totalFileMax = totalFileMax;
			return this;
		}

		public FileBizConfig init() {
			return init(1, 10, imageExts, defaultSingleFileMax, defaultSingleFileMax * 10);
		}

		public static FileBizConfig of(int min, int max, int singleFileLimit, int totalFileLimit) {
			return new FileBizConfig().init(min, max, imageExts, singleFileLimit, totalFileLimit);
		}

		public static FileBizConfig of(int min, int max) {
			return new FileBizConfig().init(min, max, imageExts, defaultSingleFileMax, defaultSingleFileMax * max);
		}

	}

	@Getter
	public enum FileBizKey implements ValueProxyImpl<FileBizKey, String> {
		/** 头像 */
		avatar("avatar", "头像"),
		/** 身份证 */
		idCard("idCard", "身份证"),
		/** 动态图片 */
		moments("moments", "动态图片"),
		/** 相册 */
		photo("album", "相册"),
		/** 用户认证 */
		avatarCert("certifiedImage", "用户认证"),
		/** 建议和投诉 */
		feedback("suggestionsComplaints", "建议和投诉"),
		/** 礼物 */
		gift("gift", "礼物"),
		/** svga */
		svga("svga", "动态图"),
		/** configImg */
		configImg("configImg", "配置图"),
		/** agent */
		agent("agent", "推广员"),
		/** 群头像 */
		groupAvatar("groupAvatar", "群头像"),
		/** banner */
		banner("banner", "banner"),
		/** banner */
		startConfig("startConfig", "启动页"),
		/** 自定义搭讪 */
		greet("greet", "搭讪图片"),
		/** 语音 */
		audio("audio", "语音"),
		/** 标签 */
		tag("tag", "标签"),
		/** 配置图 */
		single("single", "配置图"),
		/** 视频" */
		video("video", "视频"),
		/** 聊天图片 */
		chatPhoto("chatPhoto", "聊天图片"),
		/** 支付风控 */
		payRisk("payRisk", "支付风控"),
		/**  录音记录风控 */
		payRiskRecord("chatBackground", "录音记录风控");
		//
		;

		// 定义私有变量
		public final String alias;
		final ValueProxy<FileBizKey, String> proxy;

		// 构造函数，枚举类型只能为私有
		FileBizKey(String alias, String label) {
			this.alias = alias;
			this.proxy = new ValueProxy<>(this, name(), label);
		}

		public static final FileBizKey[] CACHE = values();

		public static FileBizKey of(String value) {
			return avatar.getValueOf(value);
		}

		public static FileBizKey ofAlias(String value) {
			return Arrays.stream(CACHE).filter(c -> c.getAlias().equals(value)).findFirst().orElse(null);
		}

	}

}
